/*******************************************************************************
  * @file    lcd4bit.c
  * @author  chumanhcuong@hlab.com.vn
  * @version V1.0
  * @date    26-05-2012
  * @brief   This library support for GT2
  ******************************************************************************/
/***********************************************************
**    INCLUDE
************************************************************/
#include "lcd4bit.h"
/*****************************************************************************/
/* DEFINITION OF CONSTANTS                                                   */
/*****************************************************************************/
#define IOn                       7
/*****************************************************************************/
/* DEFINITION OF TYPES OF MODULE                                             */
/*****************************************************************************/
typedef enum {RS=0,RW,EN,D0,D1,D2,D3,IO_LIMITED}LCD_PORT;
typedef enum {INSTRUCT_COMP,MODE_4BIT,LCD_5X8,CURSOR_DISABLE,CURSOR_ENABLE,CLRSCR,TOP_LINE,BOT_LINE}LCD_CMD;
/******************************************************************************/
/* DECLARATION OF VARIABLES OF MODULE                                         */
/* Declaration of local variables shall have the specifier STATIC             */
/******************************************************************************/
static const uint16_t LCDPin[IOn] ={
RS_PIN,
RW_PIN,
EN_PIN,
D0_PIN,
D1_PIN,
D2_PIN,
D3_PIN,
};
static GPIO_TypeDef* LCDPort[IOn]={
RS_PORT,
RW_PORT,
EN_PORT,
D0_PORT,
D1_PORT,
D2_PORT,
D3_PORT,
};
const uint32_t RCCPort[IOn] = {
RS_CLK,
RW_CLK,
EN_CLK,
D0_CLK,
D1_CLK,
D2_CLK,
D3_CLK,
};
static const char MaskBit[] = {0x80,0x40,0x20,0x10};
static const char ShiftBit[] = {0x07,0x06,0x05,0x04};
static const uint16_t LCDData[] = {D3,D2,D1,D0};
static const uint8_t LCDCmd[] = {0x03,0x02,0x28,0x0c,0x0f,0x01,0x80,0xc0};
/******************************************************************************/
/**    DEFINE OF INTERNAL FUNCTION                                            */
/******************************************************************************/
/**
  @brief Reset Screen Buffer
  @param None
  @retval None
  */
static void ResetScreenBuffer(void){
	int j;
	for(j=0;j<sizeof(LCD.ScreenBuffer);j++)
		  LCD.ScreenBuffer[j] = 0x00;
}


/**
  @brief LCD Clear Screen
  @param None
  @retval None
  */
static void ClearScreen(void){
	#ifdef _CLR_SPACE
		int i;
		for(i=0;i<16;i++){
				LCD.WriteData(' ');
		}		
	#endif 
	LCD.WriteCmd(LCDCmd[CLRSCR]);
}

/**
  @brief SetCursorFirstTop(), set cursor at fisrt of top line
  @param None
  @retval None
  */
static void SetCursorFirstTop(void){
	LCD.WriteCmd(LCDCmd[TOP_LINE]);
}
/**
  @brief SetCursorFirstBot(), set cursor at fisrt of bot line
  @param None
  @retval None
  */
static void SetCursorFirstBot(void){
	LCD.WriteCmd(LCDCmd[BOT_LINE]);
}
/**
  @brief SetCursorLocal(X,Y), set cursor at localtion, 
  @param 0=<X<16, 0=<Y<=1
  @retval None
  */
static void SetCursorLocal(char X, char Y){
	switch(Y){
		case 0:  LCD.WriteCmd(LCDCmd[BOT_LINE]+X);break;
		case 1:  LCD.WriteCmd(LCDCmd[TOP_LINE]+X);break;
		default: break;
	}
}
/**
  @brief LCD IO Init
  @param None
  @retval None
  */
static void IOInit(void){
	int i;
	GPIO_InitTypeDef GPIO_InitStructure;
	for(i=0;i<IOn;i++){
	   RCC_APB2PeriphClockCmd(RCCPort[i], ENABLE );	
	   GPIO_InitStructure.GPIO_Pin = LCDPin[i];
	   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
     GPIO_Init( LCDPort[i], &GPIO_InitStructure );
	}
	LCD.IOClrPin(RS);
  LCD.IOClrPin(RW);
  LCD.IOClrPin(EN);
  LCD.IOSetPin(D0);
  LCD.IOClrPin(D1);
  LCD.IOClrPin(D2);
  LCD.IOSetPin(D3);
}

/**
  @brief LCd IO Set bit
  @param None
  @retval None
  */
static void IOSetPin(int GPIO_Pin){
	if(GPIO_Pin>=RS&&GPIO_Pin<=IO_LIMITED)
		GPIO_SetBits(LCDPort[GPIO_Pin],LCDPin[GPIO_Pin]);
}
/**
  @brief LCD Clear bit
  @param None
  @retval None
  */
static void IOClrPin(int GPIO_Pin){
	if(GPIO_Pin>=RS&&GPIO_Pin<=IO_LIMITED)
		GPIO_ResetBits(LCDPort[GPIO_Pin],LCDPin[GPIO_Pin]);
}
/**
  @brief LCD Write Cmd
  @param None
  @retval None
  */
static void WriteData(int _dat){
	int i,j;
	//if is _dat
	LCD.IOSetPin(RS);
	//sent nibble
	for(j=0;j<2;j++){
			for (i=0;i<4;i++){
				if((_dat&MaskBit[i])>>ShiftBit[i])
					LCD.IOSetPin(LCDData[i]);
				else
					LCD.IOClrPin(LCDData[i]);
			}
			LCD.IOSetPin(EN);
			LCD_Delayms(3); //delay 3ms
			LCD.IOClrPin(EN);
			_dat = _dat << Nibble;
   }
	
}
/**
  @brief LCD Write Cmd
  @param LCd Command, ref at lcd4bit.h
  @retval None
  */
static void WriteCmd(int _cmd){
	int i,j;
	//if is cmd
	LCD.IOClrPin(RS);
	//sent nibble
	for(j=0;j<2;j++){
			for (i=0;i<4;i++){
				if((_cmd&MaskBit[i])>>ShiftBit[i])
					LCD.IOSetPin(LCDData[i]);
				else
					LCD.IOClrPin(LCDData[i]);
			}
			LCD.IOSetPin(EN);
			LCD_Delayms(3); //delay 3ms
			LCD.IOClrPin(EN);
			_cmd = _cmd << Nibble;
   }
}

/**
  @brief LCD Write String
  @param const string ASCII
  @retval None
  */
static void WriteString(char* str, char bsize){
	 int i;
	 for(i=0;i<bsize;i++)
		 LCD.WriteData(*str++);
}
/**
  @brief LCD Printf
  @param const string ASCII
  @retval None
  */
static void Printf(char* str, char bsize,char line){
	 int i;
	 if(line!=1)
		 LCD.SetCursorFirstBot();
	 else
		 LCD.SetCursorFirstTop();
	 for(i=0;i<bsize;i++){
		 LCD.WriteData(*str);
		 str++;
	 }
}

/**
  @brief LCD Write String
  @param const string ASCII
  @retval None
  */
static void ClearLine(char line){
	 int i;
	 switch(line){
		 case 1: LCD.SetCursorFirstTop(); for(i=0;i<16;i++)LCD.WriteData(' ');break; 
		 case 2: LCD.SetCursorFirstBot(); for(i=0;i<16;i++)LCD.WriteData(' ');break; 
		default: break;
		 
	 }
}
/******************************************************************************
** Function name: LCD_EnableCurcor()
** Description: The function enable display curcor
** Parameter X : None
** Return value: None
** Remarks: global variables used, side effects
******************************************************************************/
void LCD_EnableCurcor(void)
{
	WriteCmd(LCDCmd[CURSOR_ENABLE]);
}
/******************************************************************************
** Function name: LCD_DisableCurcor()
** Description: The function disable display curcor
** Parameter X : None
** Return value: None
** Remarks: global variables used, side effects
******************************************************************************/
void LCD_DisableCurcor(void)
{
	WriteCmd(LCDCmd[CURSOR_DISABLE]);
}
/*----------------------------------------- Public funtions ----------------------------------------------------*/
/**
  @brief LCD Init 16x2, 5x8 matrix display, disable cursor
  @param None
  @retval None
  */

int LCDInit(void){
	LCD.ClearScreen       = ClearScreen;
	LCD.SetCursorFirstTop = SetCursorFirstTop;
	LCD.SetCursorFirstBot = SetCursorFirstBot;
  LCD.SetCursorLocal    = SetCursorLocal;
	LCD.IOInit            = IOInit;
	LCD.IOSetPin          = IOSetPin;
  LCD.IOClrPin          = IOClrPin ;
	LCD.WriteData         = WriteData;
	LCD.WriteCmd          = WriteCmd;
	LCD.WriteString       = WriteString;	
	LCD.Printf            = Printf;
	LCD.StatusFlag        = true;   //is ready
	LCD.ForceDisp         = false;
	LCD.ResetBuffer       = ResetScreenBuffer;
	LCD.ClearLine         = ClearLine;
	LCD.SwitchLine        = 1;        //set display at line 1
  LCD.IOInit();
	LCD.WriteData(LCDCmd[INSTRUCT_COMP]); //write 0x03 to LCD 
	LCD_Delayms(5);  //delay 5 ms
	LCD.WriteCmd(LCDCmd[INSTRUCT_COMP]); //write 0x03 to LCD 
	LCD_Delayms(5);  //delay 5 ms
	LCD.WriteCmd(LCDCmd[INSTRUCT_COMP]); //write 0x03 to LCD 
	LCD_Delayms(5);  //delay 5 ms
	LCD.WriteCmd(LCDCmd[MODE_4BIT]);
	LCD.WriteCmd(LCDCmd[LCD_5X8]);
	LCD.WriteCmd(LCDCmd[CURSOR_DISABLE]);
	LCD.WriteCmd(LCDCmd[CLRSCR]);
	LCD.WriteCmd(LCDCmd[TOP_LINE]); 
  LCD.ResetBuffer();
	return 0;
}
/********************** End of file *************************/
/*									Copyright Cuong Chu 2013                */
/************************************************************/
